package com.com.datastructures.queue;

import java.util.ArrayDeque;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Created with IntelliJ IDEA.
 * User: Ngo Lap Thanh
 * Date: 16/06/14
 * Time: 9:54 AM
 * To change this template use File | Settings | File Templates.
 */
public class BlockingQueueUsingLocks<T> implements Queue<T> {

    final boolean fair = true;

    Lock lock;
    private Condition notEmpty;

    ArrayDeque<T> q = new ArrayDeque<>();

    public BlockingQueueUsingLocks() {
        super();
        lock =  new ReentrantLock(fair);
        notEmpty = lock.newCondition();
    }

    @Override
    public void add(T t) {
        try{
            lock.lock();
            q.add(t);
            System.out.println("\nProducer added in the queue : "
                    + t
                    + " At time "
                    + System.nanoTime()
            );
            notEmpty.signalAll();

        }
        finally{
            lock.unlock();
        }
    }

    @Override
    public T poll() {
        T t = null;
        try{
            lock.lock();

            while(q.isEmpty()){
                try{
                    notEmpty.await();
                }catch (InterruptedException ie){

                }
            }

            t = q.poll();
            System.out.println("Thread : " +
                    Thread.currentThread().getName() +
                    " polled : "+ t + " At time : "+ System.nanoTime()
            );
        }finally{
            lock.unlock();
        }
        return t;
    }
}
